/**
 * 私信数据模型
 * @author HalRui
 * @version 1.0.0
 * @description 基于Mongoose的私信数据模型，定义用户间私信的数据结构、验证规则和操作方法，支持多媒体消息和会话管理
 * @date 2025年9月27日
 */

const mongoose = require('mongoose');

// 私信ID计数器模式
const MessageIdCounterSchema = new mongoose.Schema({
    _id: { type: String, default: 'messageId' },
    sequence_value: { type: Number, default: 0 }
});

const MessageIdCounter = mongoose.model('MessageIdCounter', MessageIdCounterSchema);

// 私信模式
const MessageSchema = new mongoose.Schema({
    messageId: {
        type: Number,
        unique: true,
        required: true,
        description: '私信消息的唯一标识符，自动递增生成'
    },
    senderId: {
        type: Number,
        required: true,
        index: true,
        description: '发送者的用户ID，关联到用户信息表'
    },
    receiverId: {
        type: Number,
        required: true,
        index: true,
        description: '接收者的用户ID，关联到用户信息表'
    },
    conversationId: {
        type: String,
        required: true,
        index: true,
        description: '会话ID，用于标识两个用户之间的对话'
    },
    content: {
        type: String,
        required: true,
        maxlength: 1000,
        description: '消息内容，最大长度1000字符'
    },
    messageType: {
        type: String,
        enum: ['text', 'image', 'video', 'file'],
        default: 'text',
        description: '消息类型，支持文本、图片、视频、文件'
    },
    attachments: [{
        type: {
            type: String,
            enum: ['image', 'video', 'file'],
            description: '附件类型'
        },
        url: {
            type: String,
            description: '附件的URL地址'
        },
        filename: {
            type: String,
            description: '附件的原始文件名'
        },
        size: {
            type: Number,
            description: '附件大小，单位为字节'
        }
    }],
    isRead: {
        type: Boolean,
        default: false,
        index: true,
        description: '消息是否已读，true表示已读，false表示未读'
    },
    readAt: {
        type: Date,
        default: null,
        description: '消息阅读时间，记录接收者阅读消息的时间'
    },
    isDeleted: {
        type: Boolean,
        default: false,
        index: true,
        description: '软删除标记，true表示已删除，false表示正常状态'
    },
    deletedBy: [{
        userId: {
            type: Number,
            description: '删除消息的用户ID'
        },
        deletedAt: {
            type: Date,
            description: '删除时间'
        }
    }],
    createAt: {
        type: Date,
        default: Date.now,
        index: true,
        description: '消息的创建时间'
    },
    updateAt: {
        type: Date,
        default: Date.now,
        description: '消息的最后更新时间'
    },
    ip: {
        type: String,
        default: '',
        description: '发送者的IP地址，用于安全审计和统计分析'
    }
});

// 复合索引
MessageSchema.index({ senderId: 1, receiverId: 1, createAt: -1 });
MessageSchema.index({ conversationId: 1, createAt: -1 });
MessageSchema.index({ receiverId: 1, isRead: 1 });

// 预保存钩子
MessageSchema.pre('save', async function(next) {
    if (this.isNew) {
        try {
            const counter = await MessageIdCounter.findByIdAndUpdate(
                'messageId',
                { $inc: { sequence_value: 1 } },
                { new: true, upsert: true }
            );
            this.messageId = counter.sequence_value;
        } catch (error) {
            return next(error);
        }
    }
    this.updateAt = new Date();
    next();
});

// 静态方法

/**
 * 发送私信
 * @param {Object} messageData - 私信数据
 * @returns {Promise<Object>} 创建的私信
 */
MessageSchema.statics.sendMessage = async function(messageData) {
    const { senderId, receiverId, content, messageType = 'text', attachments = [], ip = '' } = messageData;
    
    // 生成会话ID（较小的用户ID在前）
    const conversationId = senderId < receiverId 
        ? `${senderId}_${receiverId}` 
        : `${receiverId}_${senderId}`;
    
    const message = new this({
        senderId,
        receiverId,
        conversationId,
        content,
        messageType,
        attachments,
        ip
    });
    
    await message.save();
    return message.getSafeJSON();
};

/**
 * 获取会话列表
 * @param {Object} options - 查询选项
 * @returns {Promise<Object>} 会话列表和分页信息
 */
MessageSchema.statics.getConversations = async function(options) {
    const { userId, page = 1, limit = 20 } = options;
    
    const skip = (page - 1) * limit;
    
    // 聚合查询获取每个会话的最新消息
    const conversations = await this.aggregate([
        {
            $match: {
                $or: [{ senderId: userId }, { receiverId: userId }],
                isDeleted: false,
                'deletedBy.userId': { $ne: userId }
            }
        },
        {
            $sort: { createAt: -1 }
        },
        {
            $group: {
                _id: '$conversationId',
                lastMessage: { $first: '$$ROOT' },
                unreadCount: {
                    $sum: {
                        $cond: [
                            {
                                $and: [
                                    { $eq: ['$receiverId', userId] },
                                    { $eq: ['$isRead', false] }
                                ]
                            },
                            1,
                            0
                        ]
                    }
                }
            }
        },
        {
            $sort: { 'lastMessage.createAt': -1 }
        },
        {
            $skip: skip
        },
        {
            $limit: limit
        }
    ]);
    
    // 获取总数
    const totalConversations = await this.aggregate([
        {
            $match: {
                $or: [{ senderId: userId }, { receiverId: userId }],
                isDeleted: false,
                'deletedBy.userId': { $ne: userId }
            }
        },
        {
            $group: {
                _id: '$conversationId'
            }
        },
        {
            $count: 'total'
        }
    ]);
    
    const total = totalConversations[0]?.total || 0;
    
    return {
        conversations: conversations.map(conv => ({
            conversationId: conv._id,
            lastMessage: conv.lastMessage,
            unreadCount: conv.unreadCount
        })),
        pagination: {
            page,
            limit,
            total,
            pages: Math.ceil(total / limit)
        }
    };
};

/**
 * 获取会话消息列表
 * @param {Object} options - 查询选项
 * @returns {Promise<Object>} 消息列表和分页信息
 */
MessageSchema.statics.getConversationMessages = async function(options) {
    const { conversationId, userId, page = 1, limit = 20 } = options;
    
    const skip = (page - 1) * limit;
    
    const query = {
        conversationId,
        isDeleted: false,
        'deletedBy.userId': { $ne: userId }
    };
    
    const messages = await this.find(query)
        .sort({ createAt: -1 })
        .skip(skip)
        .limit(limit)
        .lean();
    
    const total = await this.countDocuments(query);
    
    return {
        messages: messages.reverse().map(msg => ({
            messageId: msg.messageId,
            senderId: msg.senderId,
            receiverId: msg.receiverId,
            content: msg.content,
            messageType: msg.messageType,
            attachments: msg.attachments,
            isRead: msg.isRead,
            readAt: msg.readAt,
            createAt: msg.createAt
        })),
        pagination: {
            page,
            limit,
            total,
            pages: Math.ceil(total / limit)
        }
    };
};

/**
 * 标记消息为已读
 * @param {Object} options - 标记选项
 * @returns {Promise<Object>} 更新结果
 */
MessageSchema.statics.markAsRead = async function(options) {
    const { conversationId, userId, messageIds } = options;
    
    let query = {
        receiverId: userId,
        isRead: false
    };
    
    if (conversationId) {
        query.conversationId = conversationId;
    }
    
    if (messageIds && Array.isArray(messageIds)) {
        query.messageId = { $in: messageIds };
    }
    
    const result = await this.updateMany(
        query,
        {
            $set: {
                isRead: true,
                readAt: new Date(),
                updateAt: new Date()
            }
        }
    );
    
    return {
        modifiedCount: result.modifiedCount,
        matchedCount: result.matchedCount
    };
};

/**
 * 删除消息（软删除）
 * @param {number} messageId - 消息ID
 * @param {number} userId - 用户ID
 * @returns {Promise<Object>} 删除结果
 */
MessageSchema.statics.deleteMessage = async function(messageId, userId) {
    const message = await this.findOne({ messageId, isDeleted: false });
    
    if (!message) {
        throw new Error('消息不存在');
    }
    
    // 检查权限（只能删除自己发送的消息或接收的消息）
    if (message.senderId !== userId && message.receiverId !== userId) {
        throw new Error('无权限删除此消息');
    }
    
    // 添加到删除记录
    const deleteRecord = {
        userId,
        deletedAt: new Date()
    };
    
    await this.findOneAndUpdate(
        { messageId },
        {
            $push: { deletedBy: deleteRecord },
            $set: { updateAt: new Date() }
        }
    );
    
    // 如果双方都删除了，则标记为完全删除
    const updatedMessage = await this.findOne({ messageId });
    if (updatedMessage.deletedBy.length >= 2) {
        await this.findOneAndUpdate(
            { messageId },
            {
                $set: {
                    isDeleted: true,
                    updateAt: new Date()
                }
            }
        );
    }
    
    return { success: true };
};

/**
 * 删除会话
 * @param {string} conversationId - 会话ID
 * @param {number} userId - 用户ID
 * @returns {Promise<Object>} 删除结果
 */
MessageSchema.statics.deleteConversation = async function(conversationId, userId) {
    const deleteRecord = {
        userId,
        deletedAt: new Date()
    };
    
    await this.updateMany(
        {
            conversationId,
            isDeleted: false
        },
        {
            $push: { deletedBy: deleteRecord },
            $set: { updateAt: new Date() }
        }
    );
    
    return { success: true };
};

/**
 * 获取未读消息数量
 * @param {number} userId - 用户ID
 * @returns {Promise<number>} 未读消息数量
 */
MessageSchema.statics.getUnreadCount = async function(userId) {
    const count = await this.countDocuments({
        receiverId: userId,
        isRead: false,
        isDeleted: false,
        'deletedBy.userId': { $ne: userId }
    });
    
    return count;
};

/**
 * 搜索消息
 * @param {Object} options - 搜索选项
 * @returns {Promise<Object>} 搜索结果
 */
MessageSchema.statics.searchMessages = async function(options) {
    const { userId, keyword, page = 1, limit = 20 } = options;
    
    const skip = (page - 1) * limit;
    
    const query = {
        $or: [{ senderId: userId }, { receiverId: userId }],
        content: { $regex: keyword, $options: 'i' },
        isDeleted: false,
        'deletedBy.userId': { $ne: userId }
    };
    
    const messages = await this.find(query)
        .sort({ createAt: -1 })
        .skip(skip)
        .limit(limit)
        .lean();
    
    const total = await this.countDocuments(query);
    
    return {
        messages: messages.map(msg => ({
            messageId: msg.messageId,
            senderId: msg.senderId,
            receiverId: msg.receiverId,
            conversationId: msg.conversationId,
            content: msg.content,
            messageType: msg.messageType,
            createAt: msg.createAt
        })),
        pagination: {
            page,
            limit,
            total,
            pages: Math.ceil(total / limit)
        }
    };
};

/**
 * 获取消息统计
 * @param {number} userId - 用户ID
 * @returns {Promise<Object>} 消息统计
 */
MessageSchema.statics.getMessageStats = async function(userId) {
    const [sentCount, receivedCount, unreadCount] = await Promise.all([
        this.countDocuments({
            senderId: userId,
            isDeleted: false,
            'deletedBy.userId': { $ne: userId }
        }),
        this.countDocuments({
            receiverId: userId,
            isDeleted: false,
            'deletedBy.userId': { $ne: userId }
        }),
        this.getUnreadCount(userId)
    ]);
    
    return {
        sentCount,
        receivedCount,
        unreadCount,
        totalCount: sentCount + receivedCount
    };
};

// 实例方法

/**
 * 获取安全的JSON数据
 * @returns {Object} 安全的消息数据
 */
MessageSchema.methods.getSafeJSON = function() {
    return {
        messageId: this.messageId,
        senderId: this.senderId,
        receiverId: this.receiverId,
        conversationId: this.conversationId,
        content: this.content,
        messageType: this.messageType,
        attachments: this.attachments,
        isRead: this.isRead,
        readAt: this.readAt,
        createAt: this.createAt,
        updateAt: this.updateAt
    };
};

/**
 * 检查用户是否可以查看此消息
 * @param {number} userId - 用户ID
 * @returns {boolean} 是否可以查看
 */
MessageSchema.methods.canView = function(userId) {
    if (this.isDeleted) return false;
    if (this.deletedBy.some(record => record.userId === userId)) return false;
    return this.senderId === userId || this.receiverId === userId;
};

/**
 * 检查用户是否可以删除此消息
 * @param {number} userId - 用户ID
 * @returns {boolean} 是否可以删除
 */
MessageSchema.methods.canDelete = function(userId) {
    return this.senderId === userId || this.receiverId === userId;
};

const Messages = mongoose.model('Messages', MessageSchema);

module.exports = Messages;